<template>
  <a-form v-bind="restProps" :model="formState" class="x-ant-form" :class="props.className" :rules="rules">
    <a-form-item
      v-for="item in formColumns"
      :key="item.dataIndex"
      :label="item.title"
      :name="item.dataIndex"
      v-bind="validateInfos[item.dataIndex]"
      :class="item.type === 'slot' ? `form-slot-item-${item.dataIndex}` : null"
    >
      <!-- <a-input v-if="item.type === 'hidden'" type="hidden" v-model:value="formState[item.dataIndex]"/> -->
      <a-input
        v-if="!item.type || item.type === 'text'"
        v-model:value="formState[item.dataIndex]"
        :placeholder="item.placeholder || `请输入`"
        v-bind="item"
        allowClear
      />
      <a-input
        v-if="item.type === 'number'"
        v-model:value="formState[item.dataIndex]"
        :placeholder="item.placeholder || `请输入数字`"
        v-bind="item"
      />
      <a-input-password
        v-if="item.type === 'password'"
        v-model:value="formState[item.dataIndex]"
        placeholder="请输入密码"
        v-bind="item"
      ></a-input-password>
      <a-select
        v-if="item.type === 'select'"
        v-model:value="formState[item.dataIndex]"
        :placeholder="item.placeholder || `请选择`"
        :options="item.options"
        v-bind="item"
        :allowClear="true"
      ></a-select>
      <a-select
        v-if="item.type === 'multiple-select'"
        mode="multiple"
        v-model:value="formState[item.dataIndex]"
        :placeholder="item.placeholder || `请选择(可多选)`"
        :options="item.options"
        v-bind="item"
        :allowClear="true"
      ></a-select>
      <AsyncSelect
        v-if="item.type === 'async-select'"
        v-model:value="formState[item.dataIndex]"
        :placeholder="item.placeholder || `请选择`"
        :fetchOptionsPromisify="item.fetchOptionsPromisify"
        :allowClear="true"
      />
      <AsyncSelect
        v-if="item.type === 'async-multiple-select'"
        mode="multiple"
        v-model:value="formState[item.dataIndex]"
        :placeholder="item.placeholder || `请选择(可多选)`"
        :fetchOptionsPromisify="item.fetchOptionsPromisify"
        :allowClear="true"
      ></AsyncSelect>
      <a-switch
        v-if="item.type === 'boolean'"
        v-model:checked="formState[item.dataIndex]"
        :checkedValue="1"
        :unCheckedValue="0"
        v-bind="item"
      />
      <a-date-picker
        v-if="item.type === 'date'"
        v-model:value="formState[item.dataIndex]"
        valueFormat="YYYY-MM-DD HH:mm:ss"
        :show-time="{ defaultValue: moment('00:00:00', 'HH:mm:ss') }"
        placeholder="请选择日期"
      />
      <a-range-picker
        v-if="item.type === 'dateRange'"
        v-model:value="formState[item.dataIndex]"
        :show-time="{
          hideDisabledOptions: true,
          defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],
        }"
        :format="item.format ? item.format : 'YYYY-MM-DD HH:mm:ss'"
        :valueFormat="item.valueFormat ? item.valueFormat : 'YYYY-MM-DD HH:mm:ss'"
        :placeholder="item.placeholder ? item.placeholder : ['开始时间', '结束时间']"
        style="max-width: 320px"
        @openChange="handlePanelChange($event, formState[item.dataIndex])"
      />
      <a-checkbox-group
        v-if="item.type === 'multiple-checkbox'"
        v-model:value="formState[item.dataIndex]"
        :options="item.options"
      ></a-checkbox-group>
      <AsyncCheckbox
        v-if="item.type === 'async-multiple-checkbox'"
        v-model:value="formState[item.dataIndex]"
        :fetchOptionsPromisify="item.fetchOptionsPromisify"
      />
      <slot v-if="item.type === 'slot'" :name="item.dataIndex" :refFormState="formState" :formColumn="item" />
    </a-form-item>
    <slot name="footer" :rawFormState="{ ...toRaw(formState) }" :validate="validate" :refFormState="formState"> </slot>
  </a-form>
</template>

<script setup>
import { formProps } from 'ant-design-vue/es/form';
import { Form } from 'ant-design-vue';
import AsyncSelect, { FetchOptionsPromisify } from '@/components/AsyncSelect/index.vue';
import AsyncCheckbox from '@/components/AsyncCheckbox/index.vue';
import dayjs from 'dayjs';

const props = defineProps({
  ...formProps,
  dataSource: {
    type: Object,
    required: true,
  },
  formColumns: Array,
  className: String,
});

const formState = reactive(dataSource);

const rules = computed(() => {
  let ret = {};
  props.formColumns?.forEach((col) => {
    const colType = col.validateType || col.type;
    if (colType === 'slot') return;
    const rule = {
      type:
        colType === 'number' || colType === 'boolean'
          ? 'number'
          : col.type?.includes('multiple') || colType === 'array'
          ? 'array'
          : 'string',
      required: !!col.required,
      message: col.message || col.placeholder || '必填项',
    };
    if (col?.validator) {
      Reflect.set(rule, 'validator', col.validator);
    }
    ret[col.dataIndex] = [rule];
  });
  return ret;
});
const { validate, validateInfos, clearValidate } = Form.useForm(formState, rules);

watch(
  () => rules.value,
  () => clearValidate()
);

// 日期选择面板弹出的时候将默认值弹空
const handlePanelChange = (value, mode) => {
  if (value) {
    mode.length && mode.pop();
    mode.length && mode.pop();
  }
};
</script>

<style lang="scss" scoped>
// .form-even 两列等宽
.form-even {
  @include flex;
  justify-content: space-between;

  .ant-form-item {
    width: calc(50% - 32px);

    margin-bottom: $width24;
    margin-right: $width0;

    .ant-select {
      @include floatRight;
      max-width: $width256;
    }
    .ant-input,
    .ant-input-password {
      @include floatRight;
      max-width: $width256;
    }
  }
}

.x-ant-form {
  &.ant-form-inline {
    align-items: flex-start;
    :deep(.ant-form-item-explain) {
      position: absolute !important;
      right: 0;
      width: 100%;
      margin: 0 !important;
      padding: 0;
      max-width: $width256;
      font-size: $fontSize12;
    }
    .ant-select {
      max-width: $width200;
    }
  }
  .ant-select {
    min-width: 120px;
  }
}
</style>
